热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

参数声明中的静态数组索引:一个不错且鲜为人知的C语言特性

C语言的创造者们一定都热衷于让关键字的数目尽可能的少.今天将向你展示另一个可使用C99中static关键字地方.也许你已经看到过在数组的参数声明中
C语言的创造者们一定都热衷于让关键字的数目尽可能的少.今天将向你展示另一个可使用C99中static关键字地方.

也许你已经看到过在数组的参数声明中包括数组的长度:
void foo(int myArray[10]);
这样的函数仍可接收整数指针int *,但是长度[10]可以对阅读代码的人们可当作文档,传达着这相函数预期一个长度为10个整数的数组的信息.

除此之外,你还可以在括号之中加上static关键字[1]:
void bar(int myArray[static 10]);

这会告诉编译器:函数会假定传进来的实参至少有10个元素.(值得注意的是这就会把NULL排除在外!)
这样做有二个目的:
1.编译器在优化代码时能够用到这些信息[2]
2.当编译一个带有上述声明的bar时,如果传递下面三种实参[3]进去, 编译器能够警告调用者:
   a. 传递NULL
bar(NULL);
warning: null passed to a callee which requires a non-null argument [-Wnonnull]
    bar(NULL);
    ^   ~~~~

   b. 传递一个(比10)更小的数组
int a[9];
bar(a);
warning: array argument is too small; contains 9 elements, callee requires at least 10 [-Warray-bounds]
    bar(a);
    ^   ~


   c. 传递一个(比10)更大的数组

int b[11];
bar(b);

[no output]

这在当你确信函数能接收的数组的长度时很有用, 因为它既可以为阅读代码的人提供文档信息,又能让编译器帮忙捕获错误.

[1]. 也可以在括号中使用const关键字. 这会让指向myArray的指针变成指针常量.
[2].不确实编译器是否真的会优化代码, 因为寄希望于程序员们都留心编译警告信息是十分不靠谱的.
[3].使用的编译器: Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn).
原文地址:A nice, little known C feature: Static array indices in parameter declarations

看过这篇文章,但去查了C语言的参考手册,发现C99中在函数参数声明时,的确允许在数组的括号中加上限制符. 以下译自 Chap 9, 9.3 FORMAL PARAMETER DECLARATION, P296

"C99扩展了声明形式参数的语句. 一个用于修饰数组的限制符列表允许出现在数组声明者的最上层[]括号中.数组限制符(类型限制符)const, volatile和restrict将数组和指针类型等同对待.也就是说,这样的参数声明:
T A[qualifier-list e]
与以下声明等价:
T *qualifier-list e
例子:
给出这些C99中的声明:
 
     
extern int f(int x[const 10]);
extern int g(const y[10]);
 
    
那么在f函数中参数x会被看成是int * const类型(这是一个指向整型的指针常量), 而在g函数中参数y被看成它有const int *类型(也就是一个指向整型常量的指针).
译注:指向整型的指针常量,是指针的值无法改变,它指向一个可变的整型变量,也即无法改变p的值,但是*p的值是可以改的. 而后面的常量指针,是指向一个整型常量的指针,也就是p可以改变,但是*p是无法改变的.
在C99中,数组限制符static也允许出现在数组的括号之中.它对C的实现(编译器)是一个优化提示,断言实际的数组参数不能是NULL并且在进入函数体时要有所声明的类型和长度.如果没有这个限制符,NULL指针就可以当作实参作为数组传进来,就会使编译器很难知道它是安全的,比如,当在进入函数时要预取一个输入数组参数的内容时.
另外,对于原型(不能是函数定义)中的C99形式数组参数声明,其长度可以用星号(*)替代,这意味着实参将会是一个可变长数组.在原型声明中作为数组大小的任何非常量表达式与星号是等价.函数定义时必须提供一个非常量的表达式作为数组大小."

其实这里面提到的目的都是让编译器在编译时帮忙探测更多的错误.但是貌似大多数编译并不支持对函数声明数组参数的修饰,比如以上的例子在gcc中就完全没有效果,gcc不会给出任何提示.上面的建议只有static的修饰有实用意义,那就是帮忙排除NULL实参.其他的都仅有学术研究价值.
其实,在实际使用过程中,对于数组的参数,都必须同时给出另外一个参数来传达数组的长度,就像这样:
void foo(int a[], int len);
这是提倡的,也是大量普遍使用的方式.

推荐阅读
  • PHP函数的工作原理与性能分析
    在编程语言中,函数是最基本的组成单元。本文将探讨PHP函数的特点、调用机制以及性能表现,并通过实际测试给出优化建议。 ... [详细]
  • 在iOS开发中,多线程技术的应用非常广泛,能够高效地执行多个调度任务。本文将重点介绍GCD(Grand Central Dispatch)在多线程开发中的应用,包括其函数和队列的实现细节。 ... [详细]
  • 本文整理了一份基础的嵌入式Linux工程师笔试题,涵盖填空题、编程题和简答题,旨在帮助考生更好地准备考试。 ... [详细]
  • C语言是计算机科学和编程领域的基石,许多初学者在学习过程中会感到困惑。本文将详细介绍C语言的基本概念、关键语法和实用示例,帮助你快速上手C语言。 ... [详细]
  • 深入解析Java中的空指针异常及其预防策略
    空指针异常(NullPointerException,简称NPE)是Java编程中最常见的异常之一。尽管其成因显而易见,但开发人员往往容易忽视或未能及时采取措施。本文将详细介绍如何有效避免空指针异常,帮助开发者提升代码质量。 ... [详细]
  • 本文探讨了 TypeScript 中泛型的重要性和应用场景,通过多个实例详细解析了泛型如何提升代码的复用性和类型安全性。 ... [详细]
  • DirectShow Filter 开发指南
    本文总结了 DirectShow Filter 的开发经验,重点介绍了 Source Filter、In-Place Transform Filter 和 Render Filter 的实现方法。通过使用 DirectShow 提供的类,可以简化 Filter 的开发过程。 ... [详细]
  • 我自己做了一个网站图片的抓取,感觉速度有点慢抓取4000张图片可能得用15分钟左右的时间,我百度看用线程可以加快抓取,然后创建了5个线程抓取,但是5个线程是同步执行同样的操作一个图片就 ... [详细]
  • C#本随笔为个人复习巩固知识用,多从书上总结与python基础教程理解归纳得来,如有错误烦请指正面向对象的三大基本特征:封装、继承、多态 ... [详细]
  • PBO(PixelBufferObject),将像素数据存储在显存中。优点:1、快速的像素数据传递,它采用了一种叫DMA(DirectM ... [详细]
  • 稀疏数组是一种用于存储和处理大部分元素为零或相同值的数组的技术。通过记录非零元素的位置和值,稀疏数组可以显著减少存储空间和提高处理效率。 ... [详细]
  • 【线段树】  本质是二叉树,每个节点表示一个区间[L,R],设m(R-L+1)2(该处结果向下取整)左孩子区间为[L,m],右孩子区间为[m ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • Java设计模式详解:解释器模式的应用与实现
    本文详细介绍了Java设计模式中的解释器模式,包括其定义、应用场景、优缺点以及具体的实现示例。通过音乐解释器的例子,帮助读者更好地理解和应用这一模式。 ... [详细]
  • C语言编写线程池的简单实现方法
    2019独角兽企业重金招聘Python工程师标准好文章,一起分享——有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带 ... [详细]
author-avatar
ciaos
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有